#lang scribble/manual
@(require scribble/manual
          scribble/eval
          "guide-utils.rkt"
          (for-label syntax/parse))

@;{@title[#:tag "phases"]{General Phase Levels}}
@title[#:tag "phases"]{一般阶段级别}

@;{A @deftech{phase} can be thought of as a way to separate computations in
a pipeline of processes where one produces code that is used by the
next.  (E.g., a pipeline that consists of a preprocessor process, a
compiler, and an assembler.)}
@deftech{阶段（phase）}可以被看作是在进程的管道中分离出计算的方法，其中一个进程产生下一个进程使用的代码。（例如，由预处理器进程、编译器和汇编程序组成的管道）。

@;{Imagine starting two Racket processes for this purpose.  If you ignore
inter-process communication channels like sockets and files, the
processes will have no way to share anything other than the text that is
piped from the standard output of one process into the standard input of
the other.  Similarly, Racket effectively allows multiple invocations of
a module to exist in the same process but separated by phase.  Racket
enforces @emph{separation} of such phases, where different phases cannot
communicate in any way other than via the protocol of macro expansion,
where the output of one phases is the code used in the next.}
设想为此启动两个Racket过程。如果忽略套接字和文件等进程间通信通道，进程将无法共享从一个进程的标准输出管道传输到另一个进程标准输入的文本以外的任何内容。类似地，Racket有效地允许一个模块的多个调用存在于同一个进程中，但按阶段分开。Racket强制执行这种阶段的@emph{分离}，在这种情况下，不同的阶段除了通过宏展开协议之外，不能以任何方式进行通信，其中一个阶段的输出是下一个阶段使用的代码。

@;{@section{Phases and Bindings}}
@section[#:tag "Phases-and-Bindings"]{阶段和绑定}

@;{Every binding of an identifier exists in a particular phase.  The link
between a binding and its phase is represented by an integer
@deftech{phase level}.  Phase level 0 is the phase used for ``plain''
(or ``runtime'') definitions, so}
标识的每个绑定都存在于特定阶段。绑定与其阶段之间的链接由整数@deftech{阶段级别（phase-level）}表示。阶段级别0是用于“普通”（或“运行时”）定义的阶段，因此

@racketblock[
(define age 5)
]

@;{adds a binding for @racket[age] into phase level 0.  The identifier
@racket[age] can be defined at a higher phase level using
@racket[begin-for-syntax]:}
为@racket[age]添加绑定到阶段级别0中。标识@racket[age]可以用@racket[begin-for-syntax]在更高的阶段级别定义：

@racketblock[
(begin-for-syntax
  (define age 5))
]

@;{With a single @racket[begin-for-syntax] wrapper, @racket[age] is
defined at phase level 1.  We can easily mix these two definitions in
the same module or in a top-level namespace, and there is no clash
between the two @racket[age]s that are defined at different phase
levels:}
使用单个@racket[begin-for-syntax]包装器，@racket[age]在阶段级别1定义。我们可以容易地在同一个模块或顶级命名空间中混合这两个定义，并且在不同的阶段级别上定义的两个@racket[age]之间没有冲突：

@(define age-eval (make-base-eval))
@(interaction-eval #:eval age-eval (require (for-syntax racket/base)))

@interaction[#:eval age-eval
(define age 3)
(begin-for-syntax
  (define age 9))
]

@;{The @racket[age] binding at phase level 0 has a value of 3, and the
@racket[age] binding at phase level 1 has a value of 9.}
在阶段级别0的@racket[age]绑定值为3，在阶段级别1的@racket[age]绑定值为9。

@;{Syntax objects capture binding information as a first-class value.
Thus,}
语法对象将绑定信息捕获为一级值。因此，

@racketblock[#'age]

@;{is a syntax object that represents the @racket[age] binding---but
since there are two @racket[age]s (one at phase level 0 and one at
phase level 1), which one does it capture?  In fact, Racket imbues
@racket[#'age] with lexical information for all phase levels, so the
answer is that @racket[#'age] captures both.}
是一个表示@racket[age]绑定的语法对象，但由于有两个@racket[age]（一个在阶段级别0，一个在阶段级别1），它捕获的是哪一个？事实上，Racket为@racket[#'age]注入了所有阶段级别的词汇信息，所以答案是@racket[#'age]同时捕捉了这两者。

@;{The relevant binding of @racket[age] captured by @racket[#'age] is
determined when @racket[#'age] is eventually used.  As an example, we
bind @racket[#'age] to a pattern variable so we can use it in a
template, and then we @racket[eval]uate the template: @margin-note*{We
  use @racket[eval] here to demonstrate phases, but see
  @secref["reflection"] for caveats about @racket[eval].}}
@racket[#'age]捕获的@racket[age]的相关绑定是在最终使用@racket[#'age]时确定的。例如，我们将@racket[#'age]绑定到一个模式变量，以便在模板中使用它，然后@racket[eval]对模板求值：
@margin-note*{我们在这里使用@racket[eval]演示阶段，但请参见《@secref["reflection"]》了解有关@racket[eval]的警告。}

@interaction[#:eval age-eval
(eval (with-syntax ([age #'age])
        #'(displayln age)))
]

@;{The result is @racket[3] because @racket[age] is used at phase 0 level.
We can try again with the use of @racket[age] inside
@racket[begin-for-syntax]:}
结果是@racket[3]，因为@racket[age]用于0阶段级别。我们可以在@racket[begin-for-syntax]内使用@racket[age]再试一次：

@interaction[#:eval age-eval
(eval (with-syntax ([age #'age])
        #'(begin-for-syntax
            (displayln age))))
]

@;{In this case, the answer is @racket[9], because we are using
@racket[age] at phase level 1 instead of 0 (i.e.,
@racket[begin-for-syntax] evaluates its expressions at phase level 1).
So, you can see that we started with the same syntax object,
@racket[#'age], and we were able to use it in two different ways: at
phase level 0 and at phase level 1.}
在这种情况下，答案是@racket[9]，因为我们在阶段级别1使用@racket[age]，而不是0（即， @racket[begin-for-syntax]在阶段级别1求值表达式）。所以，你可以看到我们从相同的语法对象开始@racket[#'age]开始，我们可以用两种不同的方法使用它：在阶段级别0和在阶段级别1。

@;{A syntax object has a lexical context from the moment it first exists.
A syntax object that is provided from a module retains its lexical
context, and so it references bindings in the context of its source
module, not the context of its use.  The following example defines
@racket[button] at phase level 0 and binds it to @racket[0], while
@racket[see-button] binds the syntax object for @racket[button] in
module @racket[a]:}
语法对象从第一次存在时起就具有词法上下文。模块提供的语法对象保留其词法上下文，因此它引用源模块上下文中的绑定，而不是其使用上下文。以下示例在阶段级别0定义了@racket[button]，并将其绑定到@racket[0]，而@racket[see-button]则绑定了模块@racket[a]中的@racket[button]的语法对象：

@interaction[
(module a racket
  (define button 0)
  (provide (for-syntax see-button))
  @;code:comment[@#,t{Why not @racket[(define see-button #'button)]? We explain later.}
  @code:comment[@#,t{为什么不使用@racket[(define see-button #'button)]？ 我们稍后解释。}]
  (define-for-syntax see-button #'button))

(module b racket
  (require 'a)
  (define button 8)
  (define-syntax (m stx)
    see-button)
  (m))

(require 'b)
]

@;{The result of the @racket[m] macro is the value of @racket[see-button],
which is @racket[#'button] with the lexical context of the @racket[a]
module.  Even though there is another @racket[button] in @racket[b], the
second @racket[button] will not confuse Racket, because the lexical
context of @racket[#'button] (the value bound to @racket[see-button]) is
@racket[a].}
在@racket[m]宏的结果是@racket[see-button]的值，它是@racket[#'button]，带有模块@racket[a]模块的词汇上下文。即使在@racket[b]中有另一个@racket[button]，第二个@racket[button]不会混淆Racket，因为@racket[#'button]的词汇上下文（绑定到@racket[see-button]的值）是@racket[a]。

@;{Note that @racket[see-button] is bound at phase level 1 by virtue of
defining it with @racket[define-for-syntax].  Phase level 1 is needed
because @racket[m] is a macro, so its body executes at one phase higher
than the context of its definition.  Since @racket[m] is defined at
phase level 0, its body is at phase level 1, so any bindings referenced
by the body must be at phase level 1.}
请注意，通过@racket[define-for-syntax]定义@racket[see-button]，它绑定在阶段级别1。阶段级别1是必须的，因为@racket[m]是一个宏，所以它的主体执行的阶段高于其定义的上下文。由于@racket[m]是在阶段级别0定义的，因此其主体处于阶段级别1，所以由主体引用的任何绑定都必须在阶段级别1。

@; ======================================================================

@;{@section{Phases and Modules}}
@section[#:tag "Phases-and-Modules"]{阶段和模块}

@;{A @tech{phase level} is a module-relative concept.  When importing from
another module via @racket[require], Racket lets us shift imported
bindings to a phase level that is different from the original one:}
一个@tech{阶段级别（phase level）}是一个模块相关概念。当通过@racket[require]从另一个模块导入时，Racket允许我们将导入的绑定变换为与原始绑定不同的阶段级别：

@racketblock[
(require "a.rkt")                @code:comment{@;{import with no phase shift}不带阶段变换的导入}
(require (for-syntax "a.rkt"))   @code:comment{@;{shift phase by +1}通过+1变换阶段}
(require (for-template "a.rkt")) @code:comment{@;{shift phase by -1}通过-1变换阶段}
(require (for-meta 5 "a.rkt" ))  @code:comment{@;{shift phase by +5}通过+5变换阶段}
]

@;{That is, using @racket[for-syntax] in @racket[require] means that all of
the bindings from that module will have their phase levels increased by
one.  A binding that is @racket[define]d at phase level 0 and imported
with @racket[for-syntax] becomes a phase-level 1 binding:}
也就是说，在@racket[require]中使用@racket[for-syntax]意味着来自该模块的所有绑定的阶段级别都会增加。在阶段级别0为@racket[define]并用@racket[for-syntax]导入的绑定成为阶段级别1的绑定：

@interaction[
(module c racket
  (define x 0) @code:comment{@;{defined at phase level 0}在阶段级别0定义}
  (provide x))

(module d racket
  (require (for-syntax 'c))
  @code:comment{@;{has a binding at phase level 1, not 0:}在阶段级别1的绑定，而不是0：}
  #'x)
]

@;{Let's see what happens if we try to create a binding for the
@racket[#'button] syntax object at phase level 0:}
让我们看看如果我们尝试在阶段级别0为@racket[#'button]语法对象创建绑定会发生了什么：

@(define button-eval (make-base-eval))
@(interaction-eval #:eval button-eval
                   (require (for-syntax racket/base)))
@interaction[#:eval button-eval
(define button 0)
(define see-button #'button)
]

@;{Now both @racket[button] and @racket[see-button] are defined at phase
0.  The lexical context of @racket[#'button] will know that there is a
binding for @racket[button] at phase 0.  In fact, it seems like things
are working just fine if we try to @racket[eval] @racket[see-button]:}
现在在第阶段0中定义了@racket[button]和@racket[see-button]。@racket[#'button]的词汇上下文会知道在阶段0有一个绑定。事实上，如果我们尝试对@racket[see-button]进行@racket[eval]，似乎一切都很顺利：

@interaction[#:eval button-eval
(eval see-button)
]

@;{Now, let's use @racket[see-button] in a macro:}
现在，让我们在宏中使用@racket[see-button]：

@interaction[#:eval button-eval
(define-syntax (m stx)
  see-button)
(m)
]

@;{Clearly, @racket[see-button] is not defined at phase level 1, so we
cannot refer to it inside the macro body.  Let's try to use
@racket[see-button] in another module by putting the button definitions
in a module and importing it at phase level 1.  Then, we will get
@racket[see-button] at phase level 1:}
显然，@racket[see-button]在阶段1没有定义，因此我们不能在宏主体内引用它。让我们尝试在另一个模块中使用@racket[see-button]，方法是将将按钮（button）定义放在模块中，并在阶段级别1导入它。那么，我们将在阶段级别1获得@racket[see-button]：

@interaction[
(module a racket
  (define button 0)
  (define see-button #'button)
  (provide see-button))

(module b racket
  (require (for-syntax 'a)) @code:comment[@#,t{@;{gets @racket[see-button] at phase level 1}在阶段级别1获得@racket[see-button]}]
  (define-syntax (m stx)
    see-button)
  (m))
]

@;{Racket says that @racket[button] is unbound now!  When @racket[a] is
imported at phase level 1, we have the following bindings:}
Racket说@racket[button]现在已解除绑定！当在阶段级别1导入@racket[a]时，我们有以下绑定：

@racketblock[
button     @#,elem{@;{at phase level 1}在阶段级别1}
see-button @#,elem{@;{at phase level 1}在阶段级别1}
]

@;{So the macro @racket[m] can see a binding for @racket[see-button] at
phase level 1 and will return the @racket[#'button] syntax object, which
refers to @racket[button] binding at phase level 1.  But the use of
@racket[m] is at phase level 0, and there is no @racket[button] at phase
level 0 in @racket[b].  That is why @racket[see-button] needs to be
bound at phase level 1, as in the original @racket[a].  In the original
@racket[b], then, we have the following bindings:}
因此，宏@racket[m]能够在阶段级别1看到@racket[see-button]的绑定并将返回@racket[#'button]语法对象，它指的是在阶段级别1的@racket[button]绑定。但是@racket[m]的使用是在阶段级别0，在@racket[b]的阶段级别0没有@racket[button]。这就是为什么@racket[see-button]需要在阶段级别1，就像在原来的@racket[a]中一样。那么，在原来的@racket[b]中，我们有以下绑定：

@racketblock[
button     @#,elem{@;{at phase level 0}在阶段级别0}
see-button @#,elem{@;{at phase level 1}在阶段级别1}
]

@;{In this scenario, we can use @racket[see-button] in the macro, since
@racket[see-button] is bound at phase level 1.  When the macro expands,
it will refer to a @racket[button] binding at phase level 0.}
在这种情况下，我们可以在宏中使用@racket[see-button]，因为@racket[see-button]是在阶段级别1绑定的。当宏展开时，它将引用在阶段级别0的@racket[button]绑定。

@;{Defining @racket[see-button] with @racket[(define see-button
#'button)] isn't inherently wrong; it depends on how we intend to use
@racket[see-button].  For example, we can arrange for @racket[m] to
sensibly use @racket[see-button] because it puts it in a phase level 1
context using @racket[begin-for-syntax]:}
用@racket[(define see-button
#'button)]定义@racket[see-button]本身没有错；它取决于我们打算如何使用@racket[see-button]。例如，我们可以安排@racket[m]合理地使用@racket[see-button]，因为它使用@racket[begin-for-syntax]将其放在了阶段级别1的上下文中：

@interaction[
(module a racket
  (define button 0)
  (define see-button #'button)
  (provide see-button))

(module b racket
  (require (for-syntax 'a))
  (define-syntax (m stx)
    (with-syntax ([x see-button])
      #'(begin-for-syntax
          (displayln x))))
  (m))
]

@;{In this case, module @racket[b] has both @racket[button] and
@racket[see-button] bound at phase level 1.  The expansion of the macro
is}
在这种情况下，模块@racket[b]在阶段级别1上同时绑定了@racket[button]和@racket[see-button]。宏的展开是

@racketblock[
(begin-for-syntax
  (displayln button))
]

@;{which works, because @racket[button] is bound at phase level 1.}
这是可行的，因为@racket[button]是在阶段级别1绑定的。

@;{Now, you might try to cheat the phase system by importing @racket[a] at
both phase level 0 and phase level 1.  Then you would have the following
bindings}
现在，你可以通过在阶段等级0和阶段等级1中导入@racket[a]来欺骗阶段系统。然后，你将拥有以下绑定

@racketblock[
button     @#,elem{@;{at phase level 0}在阶段级别0}
see-button @#,elem{@;{at phase level 0}在阶段级别0}
button     @#,elem{@;{at phase level 1}在阶段级别1}
see-button @#,elem{@;{at phase level 1}在阶段级别1}
]

@;{You might expect now that @racket[see-button] in a macro would work, but
it doesn't:}
现在，你可能希望宏中的@racket[see-button]可以工作，但它没有：

@interaction[
(module a racket
  (define button 0)
  (define see-button #'button)
  (provide see-button))

(module b racket
  (require 'a
           (for-syntax 'a))
  (define-syntax (m stx)
    see-button)
  (m))
]

@;{The @racket[see-button] inside macro @racket[m] comes from the
@racket[(for-syntax 'a)] import.  For macro @racket[m] to work, it needs to 
have @racket[button] bound at phase 0. That binding exists---it's implied by
@racket[(require 'a)].  However, @racket[(require 'a)] and
@racket[(require (for-syntax 'a))] are @emph{different instantiations}
of the same module.  The @racket[see-button] at phase 1 only refers to
the @racket[button] at phase 1, not the @racket[button] bound at
phase 0 from a different instantiation---even from the same source
module.}
宏@racket[m]中的@racket[see-button]来自@racket[(for-syntax 'a)]导入。要使宏@racket[m]工作，需要在阶段0绑定@racket[button]。这种绑定是存在的——它由@racket[(require 'a)]表明。然而，@racket[(require 'a)]和@racket[(require (for-syntax 'a))]是同一模块的@emph{不同实例化}。阶段1的@racket[see-button]仅指第1阶段的@racket[button]，而不是在阶段0从不同实例化绑定的@racket[button]，即使来自同一个源模块。

@;{This kind of phase-level mismatch between instantiations can be repaired 
with @racket[syntax-shift-phase-level]. Recall that a syntax object like 
@racket[#'button] captures lexical information at @emph{all} phase levels. 
The problem here is that @racket[see-button] is 
invoked at phase 1, but needs to return a syntax object that can be 
evaluated at phase 0. By default, @racket[see-button] is bound to 
@racket[#'button] at the same phase level. But with 
@racket[syntax-shift-phase-level], we can make @racket[see-button] 
refer to @racket[#'button] at a different relative phase level. 
In this case, we use a phase shift of @racket[-1] to make @racket[see-button] 
at phase 1 refer to @racket[#'button] at phase 0. (Because the phase shift
happens at every level, it will also make @racket[see-button] at phase 0 
refer to @racket[#'button] at phase -1.)}
实例化之间的这种阶段级别不匹配可以用@racket[syntax-shift-phase-level]修复。回想一下，像@racket[#'button]这样的语法对象在@emph{所有}阶段级别捕获词汇信息。这里的问题是，@racket[see-button]在阶段1调用，但需要返回一个可以在阶段0进行求值的语法对象。默认情况下，@racket[see-button]在同一阶段级别绑定到@racket[#'button]。但是，使用@racket[syntax-shift-phase-level]，我们可以使@racket[see-button]在不同的相对阶段级别上引用@racket[#'button]。在这种情况下，我们使用@racket[-1]的变换使阶段1的@racket[see-button]指向阶段0的@racket[#'button]。（由于阶段变换发生在每一个级别，它也使阶段0的@racket[see-button]指向阶段-1的@racket[#'button]）

@;{Note that @racket[syntax-shift-phase-level] merely creates a reference
across phases. To make that reference work, we still need to instantiate our 
module at both phases so the reference and its target have their bindings 
available. Thus, in module @racket['b],
we still import module @racket['a] at both phase 0 and phase
1---using @racket[(require 'a (for-syntax 'a))]---so we have a phase-1 
binding for @racket[see-button] and a phase-0 binding for @racket[button].
Now macro @racket[m] will work.}
请注意，@racket[syntax-shift-phase-level]仅仅创建了一个跨阶段的引用。为了使该引用有效，我们仍然需要在两个阶段实例化模块，以便引用及其目标具有可用的绑定。因此，在模块@racket['b]中，我们仍然在阶段0和阶段1导入模块@racket['a]——使用@racket[(require 'a (for-syntax 'a))]——所以我们有一个阶段1绑定用于@racket[see-button]，一个阶段0绑定用于@racket[button]。现在宏@racket[m]就将起作用了。

@interaction[
(module a racket
  (define button 0)
  (define see-button (syntax-shift-phase-level #'button -1))
  (provide see-button))

(module b racket
  (require 'a (for-syntax 'a))
  (define-syntax (m stx)
    see-button)
  (m))

(require 'b)
]

@;{By the way, what happens to the @racket[see-button] that's bound at phase 0? 
Its @racket[#'button] binding has likewise been shifted, but to phase -1. Since 
@racket[button] itself isn't bound at phase -1, if we try to evaluate 
@racket[see-button] at phase 0, we get an error. In other words, we haven't permanently 
cured our mismatch problem---we've just shifted it to a less bothersome location.}
顺便问一下，在阶段0绑定的@racket[see-button]会发生什么变化？它的@racket[#'button]绑定也同样转移到阶段-1。由于@racket[button]本身在阶段-1没有绑定，如果我们试图在阶段0对@racket[see-button]求值，我们会得到一个错误。换句话说，我们还没有永久地解决错配问题——我们只是把它转移到一个不太麻烦的位置。

@interaction[
(module a racket
  (define button 0)
  (define see-button (syntax-shift-phase-level #'button -1))
  (provide see-button))

(module b racket
  (require 'a (for-syntax 'a))
  (define-syntax (m stx)
    see-button)
  (m))

(module b2 racket
  (require 'a)
  (eval see-button))

(require 'b2)
]

@;{Mismatches like the one above can also arise when a macro tries to match
literal bindings---using @racket[syntax-case] or @racket[syntax-parse].}
当宏试图匹配字面绑定时——使用@racket[syntax-case]或@racket[syntax-parse]，也会出现上述不匹配。

@interaction[
(module x racket
  (require (for-syntax syntax/parse)
           (for-template racket/base))

  (provide (all-defined-out))

  (define button 0)
  (define (make) #'button)
  (define-syntax (process stx)
    (define-literal-set locals (button))
    (syntax-parse stx
      [(_ (n (~literal button))) #'#''ok])))

(module y racket
  (require (for-meta 1 'x)
           (for-meta 2 'x racket/base))

  (begin-for-syntax
    (define-syntax (m stx)
      (with-syntax ([out (make)])
        #'(process (0 out)))))

  (define-syntax (p stx)
    (m))

  (p))
]

@;{In this example, @racket[make] is being used in @racket[y] at phase
level 2, and it returns the @racket[#'button] syntax object---which
refers to @racket[button] bound at phase level 0 inside @racket[x] and
at phase level 2 in @racket[y] from @racket[(for-meta 2 'x)].  The
@racket[process] macro is imported at phase level 1 from
@racket[(for-meta 1 'x)], and it knows that @racket[button] should be
bound at phase level 1.  When the @racket[syntax-parse] is executed
inside @racket[process], it is looking for @racket[button] bound at
phase level 1 but it sees only a phase level 2 binding and doesn't
match.}
在这个例子中，@racket[make]在在阶段级别2的@racket[y]中使用，它返回@racket[#'button]语法对象——它是指在@racket[x]中的阶段级别0绑定的@racket[button]，以及在@racket[(for-meta 2 'x)]中的@racket[y]内阶段级别2绑定的。@racket[process]宏是在阶段级别1从@racket[(for-meta 1 'x)]导入的，它知道@racket[button]应该绑定在阶段级别1。当@racket[syntax-parse]在@racket[process]中执行时，它正在寻找在阶段级别1绑定的@racket[button]，但它只看到阶段级别2绑定，因此不匹配。

@;{To fix the example, we can provide @racket[make] at phase level 1
relative to @racket[x], and then we import it at phase level 1 in
@racket[y]:}
为了修正这个例子，我们可以在相对于@racket[x]的阶段级别1中提供@racket[make]，然后在阶段级别1在@racket[y]中导入它：

@interaction[
(module x racket
  (require (for-syntax syntax/parse)
           (for-template racket/base))

  (provide (all-defined-out))

  (define button 0)

  (provide (for-syntax make))
  (define-for-syntax (make) #'button)
  (define-syntax (process stx)
    (define-literal-set locals (button))
    (syntax-parse stx
      [(_ (n (~literal button))) #'#''ok])))

(module y racket
  (require (for-meta 1 'x)
           (for-meta 2 racket/base))

  (begin-for-syntax
    (define-syntax (m stx)
      (with-syntax ([out (make)])
        #'(process (0 out)))))

  (define-syntax (p stx)
    (m))

  (p))

(require 'y)
]

@(close-eval age-eval)
@(close-eval button-eval)
